﻿using System;
using System.Drawing;
using System.Collections.Generic;
using System.Text;

using LowLevelGraphics.ColorSpaces;

namespace LowLevelGraphics.Histograms
{
    //TODO: improve speed even more. 

    /// <summary>
    /// Use this to sort color values....
    /// </summary>
    public class ValueSorterColorDictionary : IComparer<KeyValuePair<Color, int>>
    {
        private PROCESSING_MODE m_HistogramSortMode = PROCESSING_MODE.None;
        /// <summary>
        /// Initializes a new instance of the <see cref="ValueSorterColorDictionary"/> class.
        /// </summary>
        /// <param name="_histogramSortMode">The _histogram sort mode.</param>
        public ValueSorterColorDictionary(PROCESSING_MODE _histogramSortMode)
        {
            m_HistogramSortMode = _histogramSortMode;
        }

        #region IComparer<KeyValuePair<Color,int>> Member

        /// <summary>
        /// Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other.
        /// </summary>
        /// <param name="x">The first object to compare.</param>
        /// <param name="y">The second object to compare.</param>
        /// <returns>
        /// Value Condition Less than zero<paramref name="x"/> is less than <paramref name="y"/>.Zero<paramref name="x"/> equals <paramref name="y"/>.Greater than zero<paramref name="x"/> is greater than <paramref name="y"/>.
        /// </returns>
        public int Compare(KeyValuePair<Color, int> x, KeyValuePair<Color, int> y)
        {
            return new ValueSorter(m_HistogramSortMode).Compare(new StatisticValue(x.Key), new StatisticValue(y.Key));
        }

        #endregion
    }

    /// <summary>
    /// Value Sorter
    /// </summary>
    public class ValueSorter : IComparer<StatisticValue>
    {
        protected PROCESSING_MODE m_HistogramSortMode = PROCESSING_MODE.None;

        /// <summary>
        /// Initializes a new instance of the <see cref="ValueSorter"/> class.
        /// </summary>
        /// <param name="_sortMode">The _sort mode.</param>
        public ValueSorter(PROCESSING_MODE _sortMode)
        {
            this.m_HistogramSortMode = _sortMode;
        }

        /// <summary>
        /// Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other.
        /// </summary>
        /// <param name="x">The first object to compare.</param>
        /// <param name="y">The second object to compare.</param>
        /// <returns>
        /// Value Condition Less than zero<paramref name="x"/> is less than <paramref name="y"/>.Zero<paramref name="x"/> equals <paramref name="y"/>.Greater than zero<paramref name="x"/> is greater than <paramref name="y"/>.
        /// </returns>
        public int Compare(StatisticValue x, StatisticValue y)
        {
            int nReturnValue = -10;
            switch (m_HistogramSortMode)
            {
                case PROCESSING_MODE.A:
                    nReturnValue = Statistics.CompareA(x.A, y.A);
                    break;

                case PROCESSING_MODE.B:
                    nReturnValue = Statistics.CompareB(x.B, y.B);
                    break;

                case PROCESSING_MODE.Brightness:
                    nReturnValue = Statistics.CompareBrightness(x.Brightness, y.Brightness);
                    break;

                case PROCESSING_MODE.Color:
                    nReturnValue = Statistics.CompareColor(x.ColorValue, y.ColorValue);
                    break;

                case PROCESSING_MODE.G:
                    nReturnValue = Statistics.CompareG(x.G, y.G);
                    break;

                case PROCESSING_MODE.Hue:
                    nReturnValue = Statistics.CompareHue(x.Hue, y.Hue);
                    break;

                case PROCESSING_MODE.Luminance:
                    nReturnValue = Statistics.CompareLuminance(x.Luminance, y.Luminance);
                    break;

                case PROCESSING_MODE.MulARGB:
                    nReturnValue = Statistics.CompareMulARGB(x.MulARGB, y.MulARGB);
                    break;

                case PROCESSING_MODE.MulRGB:
                    nReturnValue = Statistics.CompareMulRGB(x.MulRGB, y.MulRGB);
                    break;

                case PROCESSING_MODE.R:
                    nReturnValue = Statistics.CompareR(x.R, y.R);
                    break;

                case PROCESSING_MODE.Saturation:
                    nReturnValue = Statistics.CompareSaturation(x.Saturation, y.Saturation);
                    break;

                case PROCESSING_MODE.SumARGB:
                    nReturnValue = Statistics.CompareSumARGB(x.SumARGB, y.SumARGB);
                    break;

                case PROCESSING_MODE.SumRGB:
                    nReturnValue = Statistics.CompareSumRGB(x.SumRGB, y.SumRGB);
                    break;
            }
            return nReturnValue;
        }
    }

    /// <summary>
    /// Color Count Sorter
    /// </summary>
    public class ColorCountSorter : IComparer<KeyValuePair<Color, int>>
    {
        #region IComparer<KeyValuePair<Color,int>> Member

        /// <summary>
        /// Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other.
        /// </summary>
        /// <param name="x">The first object to compare.</param>
        /// <param name="y">The second object to compare.</param>
        /// <returns>
        /// Value Condition Less than zero<paramref name="x"/> is less than <paramref name="y"/>.Zero<paramref name="x"/> equals <paramref name="y"/>.Greater than zero<paramref name="x"/> is greater than <paramref name="y"/>.
        /// </returns>
        public int Compare(KeyValuePair<Color, int> x, KeyValuePair<Color, int> y)
        {
            if (x.Value > y.Value)
            {
                return 1;
            }
            else if (x.Value < y.Value)
            {
                return -1;
            }
            else
            {
                return 0;
            }
        }

        #endregion
    }

    /// <summary>
    /// Histogram
    /// </summary>
    public class Statistics
    {
        private List<StatisticValue> m_aData = new List<StatisticValue>();

        private Bitmap m_WorkingBitmap = null;
        private Dictionary<Color, int> m_aColor = new Dictionary<Color, int>();
        List<KeyValuePair<Color, int>> m_aColorList = new List<KeyValuePair<Color, int>>();

        private float m_fIntegratedOpticalIntensityMean = 0;
        private float m_fMeanRG = 0.0f;
        private float m_fMeanGB = 0.0f;
        private float m_fMeanBR = 0.0f;

        private int m_nRedEnergy = 0;
        private int m_nGreenEnergy = 0;
        private int m_nBlueEnergy = 0;

        private int m_nRedBasedCount = 0;
        private int m_nGreenBasedCount = 0;
        private int m_nBlueBasedCount = 0;
        private int m_nGrayBasedCount = 0;
        private int m_nYellowBasedCount = 0;
        private int m_nCyanBasedCount = 0;
        private int m_nMagentaBasedCount = 0;

        private int m_nPureRedEnergy = 0;
        private int m_nPureGreenEnergy = 0;
        private int m_nPureBlueEnergy = 0;
        private int m_nPureYellowEnergy = 0;
        private int m_nPureCyanEnergy = 0;
        private int m_nPureMagentaEnergy = 0;
        private int m_nPureBlackEnergy = 0;
        private int m_nPureWhiteEnergy = 0;

        private int m_nMinA = 0;
        private int m_nMinR = 0;
        private int m_nMinG = 0;
        private int m_nMinB = 0;

        private int m_nMaxA = 0;
        private int m_nMaxR = 0;
        private int m_nMaxG = 0;
        private int m_nMaxB = 0;

        double m_dMeanA = 0.0f;
        double m_dMeanR = 0.0f;
        double m_dMeanG = 0.0f;
        double m_dMeanB = 0.0f;

        float m_fMedianA = 0.0f;
        float m_fMedianR = 0.0f;
        float m_fMedianG = 0.0f;
        float m_fMedianB = 0.0f;

        float m_fLuminance = 0.0f;
        float m_fMeanLuminance = 0.0f;
        float m_fMinLuminance = 10.0f;
        float m_fMaxLuminance = 0.0f;

        float m_fBrightness = 0.0f;
        float m_fMeanBrightness = 0.0f;
        float m_fMinBrightness = 10.0f;
        float m_fMaxBrightness = 0.0f;

        float m_fHue = 0.0f;
        float m_fMeanHue = 0.0f;
        float m_fMinHue = 0.0f;
        float m_fMaxHue = 10.0f;

        float m_fSaturation = 0.0f;
        float m_fMeanSaturation = 0.0f;
        float m_fMinSaturation = 10.0f;
        float m_fMaxSaturation = 0.0f;

        float fIntegratedOpticalIntensityMean = 0.0f;

        /// <summary>
        /// Initializes a new instance of the <see cref="Histogram"/> class.
        /// </summary>
        public Statistics()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Histogram"/> class.
        /// </summary>
        /// <param name="_bitmap">The _bitmap.</param>
        public Statistics(UnsafeBitmap _bitmap)
            : this(_bitmap, 1, 1)
        {
        }

        /// <summary>
        /// Histogramm
        /// </summary>
        /// <param name="_aValue"></param>
        public Statistics(List<StatisticValue> _aValue)
        {
            this.m_aData = _aValue;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Histogram"/> class.
        /// </summary>
        /// <param name="_bitmap">The _bitmap.</param>
        /// <param name="nXStep">The n X step.</param>
        /// <param name="nYStep">The n Y step.</param>
        public Statistics(UnsafeBitmap _bitmap, int nXStep, int nYStep)
            : this(_bitmap, new Rectangle(0, 0, _bitmap.Width, _bitmap.Height), nXStep, nYStep)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Histogram"/> class.
        /// </summary>
        /// <param name="_bitmap">The _bitmap.</param>
        /// <param name="_rect">The _rect.</param>
        /// <param name="_nXStep">The _n X step.</param>
        /// <param name="_nYStep">The _n Y step.</param>
        public Statistics(UnsafeBitmap _bitmap, Rectangle _rect, int _nXStep, int _nYStep)
        {
            Calcvalues(_bitmap, _rect, _nXStep, _nYStep);
        }

        /// <summary>
        /// Calculates tha values out of the specified _bitmap.
        /// </summary>
        /// <param name="_bitmap">The _bitmap.</param>
        /// <param name="_rect">The _rect.</param>
        /// <param name="nXStep">The n X step.</param>
        /// <param name="nYStep">The n Y step.</param>
        private void Calcvalues(UnsafeBitmap _bitmap, Rectangle _rect, int nXStep, int nYStep)
        {
            Color colorAverage = Color.Transparent;
            UnsafeBitmap bitmap = _bitmap;

            double dMeanA = 0.0f;
            double dMeanR = 0.0f;
            double dMeanG = 0.0f;
            double dMeanB = 0.0f;

            int nRedEnergy = 0;
            int nGreenEnergy = 0;
            int nBlueEnergy = 0;

            float fMedianA = 0.0f;
            float fMedianR = 0.0f;
            float fMedianG = 0.0f;
            float fMedianB = 0.0f;

            int nR = 0;
            int nMinR = 255;
            int nMaxR = 0;

            int nG = 0;
            int nMinG = 255;
            int nMaxG = 0;

            int nB = 0;
            int nMinB = 255;
            int nMaxB = 0;

            int nA = 0;
            int nMinA = 255;
            int nMaxA = 0;

            float fMeanRG = 0.0f;
            float fMeanGB = 0.0f;
            float fMeanBR = 0.0f;

            float fLuminance = 0.0f;
            float fMinLuminance = 10.0f;
            float fMaxLuminance = 0.0f;

            float fBrightness = 0.0f;
            float fMeanBrightness = 0.0f;
            float fMinBrightness = 10.0f;
            float fMaxBrightness = 0.0f;

            float fHue = 0.0f;
            float fMeanHue = 0.0f;
            float fMinHue = 0.0f;
            float fMaxHue = 10.0f;

            float fSaturation = 0.0f;
            float fMeanSaturation = 0.0f;
            float fMinSaturation = 10.0f;
            float fMaxSaturation = 0.0f;

            int nIntegratedOpticalIntensity = 0;
            float fIntegratedOpticalIntensityMean = 0.0f;

            int nRedBasedCount = 0;
            int nGreenBasedCount = 0;
            int nBlueBasedCount = 0;
            int nGrayBasedCount = 0;
            int nYellowBasedCount = 0;
            int nCyanBasedCount = 0;
            int nMagentaBasedCount = 0;

            int nPureRedEnergy = 0;
            int nPureGreen = 0;
            int nPureBlueEnergy = 0;
            int nPureYellowEnergy = 0;
            int nPureCyanEnergy = 0;
            int nPureMagentaEnergy = 0;
            int nPureBlack = 0;
            int nPureWhite = 0;
            int nWidth = bitmap.Width;
            int nHeight = bitmap.Height;
            float nPixelCount = nWidth * nHeight;

            string sText = string.Empty;
            int nGrayValue = -1;
            
            StatisticValue histogramValue = null;

            Color color = Color.Empty;
            for (int y = _rect.Top; y < _rect.Bottom; y += nYStep)
            {
                for (int x = _rect.Left; x < _rect.Right; x += nXStep)
                {
                    color = bitmap.GetPixel(x, y);
                    if (this.m_aColor.ContainsKey(color))
                    {
                        continue;
                    }
                    nA = color.A;
                    if (nA > nMaxA) nMaxA = nA;
                    if (nA < nMinA) nMinA = nA;

                    nR = color.R;
                    if (nR > nMaxR) nMaxR = nR;
                    if (nR < nMinR) nMinR = nR;

                    nG = color.G;
                    if (nG > nMaxG) nMaxG = nG;
                    if (nG < nMinG) nMinG = nG;

                    nB = color.B;
                    if (nB > nMaxB) nMaxB = nB;
                    if (nB < nMinB) nMinB = nB;

                    fBrightness = color.GetBrightness();
                    fMeanBrightness += fBrightness;
                    if (fBrightness > fMaxBrightness) fMaxBrightness = fBrightness;
                    if (fBrightness < fMinBrightness) fMinBrightness = fBrightness;

                    fHue = color.GetHue();
                    fMeanHue += fHue;
                    if (fHue > fMaxHue) fMaxHue = fHue;
                    if (fHue < fMinHue) fMinHue = fHue;

                    fSaturation = color.GetSaturation();
                    fMeanSaturation += fSaturation;
                    if (fSaturation > fMaxSaturation) fMaxSaturation = fSaturation;
                    if (fSaturation < fMinSaturation) fMinSaturation = fSaturation;

                    dMeanA += nA;
                    dMeanR += nR;
                    dMeanG += nG;
                    dMeanB += nB;

                    nRedEnergy += nR;
                    nGreenEnergy += nG;
                    nBlueEnergy += nB;

                    sText = ColorFunctions.RGBMaxLetters(color);
                    if (sText == "R")
                    {
                        nRedBasedCount++;
                        if (nG == 0 && nB == 0)
                        {
                            nPureRedEnergy += nR;
                        }
                    }
                    else if (sText == "G")
                    {
                        nGreenBasedCount++;
                        if (nR == 0 && nB == 0)
                        {
                            nPureGreen += nG;
                        }
                    }
                    else if (sText == "B")
                    {
                        nBlueBasedCount++;
                        if (nR == 0 && nG == 0)
                        {
                            nPureBlueEnergy += nB;
                        }
                    }
                    else if (sText == "RG")
                    {
                        nYellowBasedCount++;
                        if (nB == 0)
                        {
                            nPureYellowEnergy += nR + nG;
                        }
                    }
                    else if (sText == "RB")
                    {
                        nMagentaBasedCount++;
                        if (nG == 0)
                        {
                            nPureMagentaEnergy += nR + nB;
                        }
                    }
                    else if (sText == "GB")
                    {
                        nCyanBasedCount++;
                        if (nR == 0)
                        {
                            nPureCyanEnergy += nG + nB;
                        }
                    }

                    nGrayValue = bitmap.GetGrayPixelValue(x, y);
                    nIntegratedOpticalIntensity += nGrayValue;
                    fIntegratedOpticalIntensityMean += nGrayValue;


                    histogramValue = new StatisticValue(color, new Point(x, y), false);
                    histogramValue.m_nGrayValue = nGrayValue;
                    histogramValue.m_A = nA;
                    histogramValue.m_R = nR;
                    histogramValue.m_G = nG;
                    histogramValue.m_B = nB;
                    histogramValue.m_fBrightness = fBrightness;
                    histogramValue.m_fHue = fHue;
                    histogramValue.m_fLuminance = ColorFunctions.GetLuminance(color);

                    histogramValue.m_fSaturation = fSaturation;
                    histogramValue.m_nMulARGB = nA * nR * nG * nB;
                    histogramValue.m_nMulRGB = nR * nG * nB;
                    histogramValue.m_nSumARGB = nA + nR + nG + nB;
                    histogramValue.m_nSumRGB = nR + nG + nB;

                    if (!this.m_aColor.ContainsKey(color))
                    {
                        this.m_aData.Add(histogramValue);
                    }
                    if (this.m_aColor.ContainsKey(color))
                    {
                        this.m_aColor[color]++;
                    }
                    else
                    {
                        m_aColor.Add(color, 1);
                    }
                }
            }

            dMeanA = dMeanA / nPixelCount;
            dMeanR = dMeanR / nPixelCount;
            dMeanG = dMeanG / nPixelCount;
            dMeanB = dMeanB / nPixelCount;

            fIntegratedOpticalIntensityMean = fIntegratedOpticalIntensityMean / nPixelCount;
            fMeanHue = fMeanHue / nPixelCount;
            fMeanSaturation = fMeanSaturation / nPixelCount;
            fMeanBrightness = fMeanBrightness / nPixelCount;

            fMeanRG = (float)dMeanR / (float)dMeanG;
            fMeanGB = (float)dMeanG / (float)dMeanB;
            fMeanBR = (float)dMeanB / (float)dMeanR;

            foreach (KeyValuePair<Color, int> keyValuePair in m_aColor)
            {
                m_aColorList.Add(keyValuePair);
            }

            //assign values to class properties
            m_fIntegratedOpticalIntensityMean = fIntegratedOpticalIntensityMean;

            m_fMinSaturation = fMinSaturation;
            m_fMaxSaturation = fMaxSaturation;
            m_fMeanSaturation = fMeanSaturation;

            m_fMinLuminance = fMinLuminance;
            m_fMaxLuminance = fMaxLuminance;
            //m_fMeanLuminance = fMeanLuminance;

            m_fMeanBrightness = fMeanBrightness;
            m_fMaxBrightness = fMaxBrightness;
            m_fMinBrightness = fMinBrightness;

            m_fMinHue = fMinHue;
            m_fMaxHue = fMaxHue;
            m_fMeanHue = fMeanHue;

            m_nRedBasedCount = nRedBasedCount;
            m_nGreenBasedCount = nGreenBasedCount;
            m_nBlueBasedCount = nBlueBasedCount;
            m_nYellowBasedCount = nYellowBasedCount;
            m_nMagentaBasedCount = nMagentaBasedCount;
            m_nCyanBasedCount = nCyanBasedCount;

            m_nPureRedEnergy = nPureRedEnergy;
            m_nPureGreenEnergy = nPureGreen;
            m_nPureBlueEnergy = nPureBlueEnergy;
            m_nPureYellowEnergy = nPureYellowEnergy;
            m_nPureMagentaEnergy = nPureMagentaEnergy;
            m_nPureCyanEnergy = nPureCyanEnergy;

            m_dMeanA = dMeanA;
            m_dMeanR = dMeanR;
            m_dMeanG = dMeanG;
            m_dMeanB = dMeanB;

            m_fMeanRG = fMeanRG;
            m_fMeanBR = fMeanBR;
            m_fMeanGB = fMeanGB;
            m_fMeanHue = fMeanHue;

            m_nMinA = nMinA;
            m_nMinR = nMinR;
            m_nMinG = nMinG;
            m_nMinB = nMinB;

            m_nMaxA = nMaxA;
            m_nMaxR = nMaxR;
            m_nMaxG = nMaxG;
            m_nMaxB = nMaxB;

            m_nRedEnergy = nRedEnergy;
            m_nGreenEnergy = nGreenEnergy;
            m_nBlueEnergy = nBlueEnergy;


            Color colorMedian = Color.Transparent;
            int nIndex1 = -1;
            int nIndex2 = -1;

            //float fIndex = m_aData.Count / 2.0f;
            //if (fIndex != (int)fIndex)
            //{
            //    nIndex1 = (int)Math.Round(fIndex);
            //    nIndex2 = nIndex1+1;
            //    Color color1 = this.m_aData[nIndex1].Color;
            //    Color color2 = this.m_aData[nIndex2].Color;
            //    m_fMedianA = (color1.A + color2.A)/2;
            //    m_fMedianR = (color1.R + color2.R)/2;
            //    m_fMedianG = (color1.G + color2.G)/2;
            //    m_fMedianB = (color1.B + color2.B)/2;
            //}
            //else
            //{
            //    nIndex1 = (int)Math.Round(fIndex);
            //    colorMedian = this.m_aData[nIndex1].Color;
            //    m_fMedianA = colorMedian.A;
            //    m_fMedianR = colorMedian.R;
            //    m_fMedianG = colorMedian.G;
            //    m_fMedianB = colorMedian.B;
            //}
        }

        /// <summary>
        /// Determines whether [contains] [the specified _color].
        /// </summary>
        /// <param name="_color">The _color.</param>
        /// <returns>
        /// 	<c>true</c> if [contains] [the specified _color]; otherwise, <c>false</c>.
        /// </returns>
        private bool Contains(Color _color)
        {
            foreach (StatisticValue histogram in this.m_aData)
            {
                if (histogram.Color == _color)
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// Gets the pure black energy.
        /// </summary>
        /// <value>The pure black energy.</value>
        public int PureBlackEnergy
        {
            get { return m_nPureBlackEnergy; }
        }

        /// <summary>
        /// Gets the pure white energy.
        /// </summary>
        /// <value>The pure white energy.</value>
        public int PureWhiteEnergy
        {
            get { return m_nPureWhiteEnergy; }
        }

        /// <summary>
        /// Gets the pure red energy.
        /// </summary>
        /// <value>The pure red energy.</value>
        public int PureRedEnergy
        {
            get { return m_nPureRedEnergy; }
        }

        /// <summary>
        /// Gets the pure green enery.
        /// </summary>
        /// <value>The pure green enery.</value>
        public int PureGreenEnery
        {
            get { return m_nPureGreenEnergy; }
        }

        /// <summary>
        /// Gets the pure blue energy.
        /// </summary>
        /// <value>The pure blue energy.</value>
        public int PureBlueEnergy
        {
            get { return m_nPureBlueEnergy; }
        }

        /// <summary>
        /// Gets the pure yellow energy.
        /// </summary>
        /// <value>The pure yellow energy.</value>
        public int PureYellowEnergy
        {
            get { return m_nPureYellowEnergy; }
        }

        /// <summary>
        /// Gets the pure cyan energy.
        /// </summary>
        /// <value>The pure cyan energy.</value>
        public int PureCyanEnergy
        {
            get { return m_nPureCyanEnergy; }
        }

        /// <summary>
        /// Gets the pure magenta energy.
        /// </summary>
        /// <value>The pure magenta energy.</value>
        public int PureMagentaEnergy
        {
            get { return m_nPureMagentaEnergy; }
        }

        /// <summary>
        /// Gets the red based count.
        /// </summary>
        /// <value>The red based count.</value>
        public int RedBasedCount
        {
            get { return m_nRedBasedCount; }
        }

        /// <summary>
        /// Gets the green based count.
        /// </summary>
        /// <value>The green based count.</value>
        public int GreenBasedCount
        {
            get { return m_nGreenBasedCount; }
        }

        /// <summary>
        /// Gets the blue based count.
        /// </summary>
        /// <value>The blue based count.</value>
        public int BlueBasedCount
        {
            get { return m_nBlueBasedCount; }
        }

        /// <summary>
        /// Gets the yellow based count.
        /// </summary>
        /// <value>The yellow based count.</value>
        public int YellowBasedCount
        {
            get { return m_nYellowBasedCount; }
        }

        /// <summary>
        /// Gets the cyan based count.
        /// </summary>
        /// <value>The cyan based count.</value>
        public int CyanBasedCount
        {
            get { return m_nCyanBasedCount; }
        }

        /// <summary>
        /// Gets the magenta based count.
        /// </summary>
        /// <value>The magenta based count.</value>
        public int MagentaBasedCount
        {
            get { return m_nMagentaBasedCount; }
        }

        /// <summary>
        /// Gets the mean brightness.
        /// </summary>
        /// <value>The mean brightness.</value>
        public float MeanBrightness
        {
            get { return m_fMeanBrightness; }
        }

        /// <summary>
        /// Gets the min brightness.
        /// </summary>
        /// <value>The min brightness.</value>
        public float MinBrightness
        {
            get { return m_fMinBrightness; }
        }

        /// <summary>
        /// Gets the max brightness.
        /// </summary>
        /// <value>The max brightness.</value>
        public float MaxBrightness
        {
            get { return m_fMaxBrightness; }
        }

        /// <summary>
        /// Gets the mean hue.
        /// </summary>
        /// <value>The mean hue.</value>
        public float MeanHue
        {
            get { return m_fMeanHue; }
        }

        /// <summary>
        /// Gets the max hue.
        /// </summary>
        /// <value>The max hue.</value>
        public float MaxHue
        {
            get { return m_fMaxHue; }
        }

        /// <summary>
        /// Gets the min hue.
        /// </summary>
        /// <value>The min hue.</value>
        public float MinHue
        {
            get { return m_fMinHue; }
        }

        /// <summary>
        /// Gets the mean saturation.
        /// </summary>
        /// <value>The mean saturation.</value>
        public float MeanSaturation
        {
            get { return m_fMeanSaturation; }
        }

        /// <summary>
        /// Gets the min saturation.
        /// </summary>
        /// <value>The min saturation.</value>
        public float MinSaturation
        {
            get { return m_fMinSaturation; }
        }

        /// <summary>
        /// Gets the max saturation.
        /// </summary>
        /// <value>The max saturation.</value>
        public float MaxSaturation
        {
            get { return m_fMaxSaturation; }
        }

        /// <summary>
        /// Gets the mean luminance.
        /// </summary>
        /// <value>The mean luminance.</value>
        public float MeanLuminance
        {
            get { return m_fMeanLuminance; }
        }

        /// <summary>
        /// Gets the min luminance.
        /// </summary>
        /// <value>The min luminance.</value>
        public float MinLuminance
        {
            get { return m_fMinLuminance; }
        }

        /// <summary>
        /// Gets the max luminance.
        /// </summary>
        /// <value>The max luminance.</value>
        public float MaxLuminance
        {
            get { return m_fMaxLuminance; }
        }

        /// <summary>
        /// Gets the median A.
        /// </summary>
        /// <value>The median A.</value>
        public float MedianA
        {
            get { return m_fMedianA; }
        }

        /// <summary>
        /// Gets the median R.
        /// </summary>
        /// <value>The median R.</value>
        public float MedianR
        {
            get { return m_fMedianR; }
        }

        /// <summary>
        /// Gets the median G.
        /// </summary>
        /// <value>The median G.</value>
        public float MedianG
        {
            get { return m_fMedianG; }
        }

        /// <summary>
        /// Gets the median B.
        /// </summary>
        /// <value>The median B.</value>
        public float MedianB
        {
            get { return m_fMedianB; }
        }

        /// <summary>
        /// Gets the mean A.
        /// </summary>
        /// <value>The mean A.</value>
        public double MeanA
        {
            get { return m_dMeanA; }
        }

        /// <summary>
        /// Gets the mean R.
        /// </summary>
        /// <value>The mean R.</value>
        public double MeanR
        {
            get { return m_dMeanR; }
        }

        /// <summary>
        /// Gets the mean G.
        /// </summary>
        /// <value>The mean G.</value>
        public double MeanG
        {
            get { return m_dMeanG; }
        }

        /// <summary>
        /// Gets the mean B.
        /// </summary>
        /// <value>The mean B.</value>
        public double MeanB
        {
            get { return m_dMeanB; }
        }

        /// <summary>
        /// Gets the integrated optical intensity mean.
        /// </summary>
        /// <value>The integrated optical intensity mean.</value>
        public float IntegratedOpticalIntensityMean
        {
            get { return m_fIntegratedOpticalIntensityMean; }
        }

        /// <summary>
        /// Gets the mean RG.
        /// </summary>
        /// <value>The mean RG.</value>
        public float MeanRG
        {
            get { return m_fMeanRG; }
        }

        /// <summary>
        /// Gets the mean GB.
        /// </summary>
        /// <value>The mean GB.</value>
        public float MeanGB
        {
            get { return m_fMeanGB; }
        }

        /// <summary>
        /// Gets the mean BR.
        /// </summary>
        /// <value>The mean BR.</value>
        public float MeanBR
        {
            get { return m_fMeanBR; }
        }

        /// <summary>
        /// Gets the min R.
        /// </summary>
        /// <value>The min R.</value>
        public int MinR
        {
            get { return m_nMinR; }
        }

        /// <summary>
        /// Gets the max R.
        /// </summary>
        /// <value>The max R.</value>
        public int MaxR
        {
            get { return m_nMaxR; }
        }

        /// <summary>
        /// Gets the min G.
        /// </summary>
        /// <value>The min G.</value>
        public int MinG
        {
            get { return m_nMinG; }
        }

        /// <summary>
        /// Gets the max G.
        /// </summary>
        /// <value>The max G.</value>
        public int MaxG
        {
            get { return m_nMaxG; }
        }

        /// <summary>
        /// Gets the min B.
        /// </summary>
        /// <value>The min B.</value>
        public int MinB
        {
            get { return m_nMinB; }
        }

        /// <summary>
        /// Gets the max B.
        /// </summary>
        /// <value>The max B.</value>
        public int MaxB
        {
            get { return m_nMaxB; }
        }

        /// <summary>
        /// Integrated Optical Intensity is the sum of the graylevels of all
        /// pixels in the object. It reflects the "mass" or "weight" of the objects
        /// and is numerically equal to multiplied by the mean interior gray level
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public int IntegratedOpticalIntensity(UnsafeBitmap _bitmap)
        {
            UnsafeBitmap bitmap = _bitmap;
            int nSum = 0;

            int nHeight = bitmap.Height;
            int nWidth = bitmap.Width;

            for (int y = 0; y < nHeight; y++)
            {
                for (int x = 0; x < nWidth; x++)
                {
                    nSum += ColorFunctions.Gray(bitmap.GetPixel(x, y));
                }
            }
            bitmap.Dispose();
            return nSum;
        }

        //TODO: Histogramm, GrayLevelStandardDeviation
        /// <summary>
        /// Grays the level standard deviation.
        /// </summary>
        /// <returns></returns>
        public int GrayLevelStandardDeviation()
        {
            return 0;
        }

        //TODO: Histogramm, Entropy
        /// <summary>
        /// Entropies this instance.
        /// </summary>
        /// <returns></returns>
        public int Entropy()
        {
            return 0;
        }

        //TODO
        /// <summary>
        /// Energies this instance.
        /// </summary>
        /// <returns></returns>
        public int Energy()
        {
            return 0;
        }

        /// <summary>
        /// Averages the color of the cross.
        /// </summary>
        /// <param name="_bitmap">The _bitmap.</param>
        /// <returns></returns>
        public static Bitmap AverageCrossColor(Bitmap _bitmap)
        {
            return AverageCrossColor(_bitmap, 1, 1);
        }

        /// <summary>
        /// Averages the color of the cross.
        /// </summary>
        /// <param name="_bitmap">The _bitmap.</param>
        /// <param name="nXStep">The n X step.</param>
        /// <param name="nYStep">The n Y step.</param>
        /// <returns></returns>
        public static Bitmap AverageCrossColor(Bitmap _bitmap, int nXStep, int nYStep)
        {
            int x = 0;
            int y = 0;

            UnsafeBitmap bitmap = _bitmap;
            Bitmap bmpTemp = new Bitmap(bitmap.Width, bitmap.Height);
            UnsafeBitmap bmp2 = bmpTemp;

            int nHeight = bitmap.Height;
            int nWidth = bitmap.Width;

            int nXMid = bitmap.Width / 2;
            int nYMid = bitmap.Height / 2;

            for (x = 0; x < nWidth; x += nXStep)
            {
                for (y = 0; y < nHeight; y += nYStep)
                {
                    Color colorX = Color.Transparent;
                    Color colorY = Color.Transparent;
                    if (x < nXMid)
                    {
                        colorX = GetAverageXColor(bitmap, 0, x, y);
                    }
                    else
                    {
                        colorX = GetAverageXColor(bitmap, 0, nWidth - 1 - x, y);
                    }
                    if (y < nYMid)
                    {
                        colorY = GetAverageYColor(bitmap, 0, y, x);
                    }
                    else
                    {
                        colorY = GetAverageYColor(bitmap, 0, nHeight - 1 - y, y);
                    }
                    Color colorAvg = ColorFunctions.AverageColor(new List<Color> { colorX, colorY });
                    bmp2.SetPixel(x, y, colorAvg);
                }
            }
            bitmap.Dispose();
            bmpTemp = (Bitmap)bmp2.InternalBitmap.Clone();
            bmp2.Dispose();
            return bmpTemp;
        }

        //TODO: optimize a LOT!
        //use a grid (only average color calculations in grid!!!)
        //public static Bitmap AverageCrossHue(Bitmap bitmap, Size sz) <= sz = sizeGridX, sizeGridY

        /// <summary>
        /// Averages the cross hue.
        /// </summary>
        /// <param name="_bitmap">The _bitmap.</param>
        /// <returns></returns>
        public static Bitmap AverageCrossHue(Bitmap _bitmap)
        {
            int x = 0;
            int y = 0;

            UnsafeBitmap bitmap = _bitmap;
            UnsafeBitmap bmp2 = bitmap;

            int nXMid = bitmap.Width / 2;
            int nYMid = bitmap.Height / 2;
            float fValue = 0.0f;

            int nHeight = bitmap.Height;
            int nWidth = bitmap.Width;

            for (x = 0; x < nWidth; x++)
            {
                for (y = 0; y < nHeight; y++)
                {
                    float fXHue = 0.0f;
                    float fYHue = 0.0f;
                    if (x < nXMid)
                    {
                        fXHue = GetAverageXHue(bitmap, 0, x, y);
                    }
                    else
                    {
                        fXHue = GetAverageXHue(bitmap, 0, nWidth - 1 - x, y);
                    }
                    if (y < nYMid)
                    {
                        fYHue = GetAverageYHue(bitmap, 0, y, x);
                    }
                    else
                    {
                        fYHue = GetAverageYHue(bitmap, 0, nHeight - 1 - y, y);
                    }
                    fValue = (fXHue + fYHue) / 2;

                    Color color = Color.FromArgb(0, 0, (int)(fValue * 0.708333333f));
                    bmp2.SetPixel(x, y, color);
                }
            }
            bmp2.Dispose();
            return bmp2.InternalBitmap;
        }

        /// <summary>
        /// Gets the average X hue.
        /// </summary>
        /// <param name="bmp">The BMP.</param>
        /// <param name="nStartX">The n start X.</param>
        /// <param name="nEndX">The n end X.</param>
        /// <param name="nY">The n Y.</param>
        /// <returns></returns>
        private static float GetAverageXHue(UnsafeBitmap bmp, int nStartX, int nEndX, int nY)
        {
            List<float> aHue = new List<float>();
            for (int x = nStartX; x < nEndX; x++)
            {
                aHue.Add(bmp.GetPixel(x, nY).GetHue());
            }
            return ColorFunctions.AverageHue(aHue);
        }

        /// <summary>
        /// Gets the average Y hue.
        /// </summary>
        /// <param name="bmp">The BMP.</param>
        /// <param name="nStartY">The n start Y.</param>
        /// <param name="nEndY">The n end Y.</param>
        /// <param name="nX">The n X.</param>
        /// <returns></returns>
        private static float GetAverageYHue(UnsafeBitmap bmp, int nStartY, int nEndY, int nX)
        {
            List<float> aHue = new List<float>();
            for (int y = nStartY; y < nEndY; y++)
            {
                aHue.Add(bmp.GetPixel(nX, y).GetHue());
            }
            return ColorFunctions.AverageHue(aHue);
        }

        /// <summary>
        /// Gets the average color of the X.
        /// </summary>
        /// <param name="bmp">The BMP.</param>
        /// <param name="nStartX">The n start X.</param>
        /// <param name="nEndX">The n end X.</param>
        /// <param name="nY">The n Y.</param>
        /// <returns></returns>
        private static Color GetAverageXColor(UnsafeBitmap bmp, int nStartX, int nEndX, int nY)
        {
            List<Color> aColor = new List<Color>();
            for (int x = nStartX; x < nEndX; x++)
            {
                aColor.Add(bmp.GetPixel(x, nY));
            }
            return ColorFunctions.AverageColor(aColor);
        }

        /// <summary>
        /// Gets the average color of the Y.
        /// </summary>
        /// <param name="bmp">The BMP.</param>
        /// <param name="nStartY">The n start Y.</param>
        /// <param name="nEndY">The n end Y.</param>
        /// <param name="nX">The n X.</param>
        /// <returns></returns>
        private static Color GetAverageYColor(UnsafeBitmap bmp, int nStartY, int nEndY, int nX)
        {
            List<Color> aColor = new List<Color>();
            for (int y = nStartY; y < nEndY; y++)
            {
                aColor.Add(bmp.GetPixel(nX, y));
            }
            return ColorFunctions.AverageColor(aColor);
        }

        /// <summary>
        /// Gets the average Y brightness.
        /// </summary>
        /// <returns></returns>
        private static float GetAverageYBrightness()
        {
            return 0.0f;
        }

        /// <summary>
        /// Gets the average X brightness.
        /// </summary>
        /// <returns></returns>
        private static float GetAverageXBrightness()
        {
            return 0.0f;
        }

        /// <summary>
        /// Columnwise measuring of saturation
        /// This is done by first measuring the average Color of this column
        /// </summary>
        /// <param name="bitmap"></param>
        /// <returns></returns>
        public static Bitmap AverageHue(Bitmap bitmap)
        {
            int x = 0;
            int y = 0;

            Bitmap bmp2 = new Bitmap(bitmap.Width, bitmap.Height);
            Graphics g = Graphics.FromImage(bmp2);

            List<float> aAvgHue = new List<float>();
            g.FillRectangle(Brushes.Black, new Rectangle(0, 0, bmp2.Width, bmp2.Height));

            int nHeight = bitmap.Height;
            int nWidth = bitmap.Width;

            for (x = 0; x < nWidth; x++)
            {
                for (y = 0; y < nHeight; y++)
                {
                    aAvgHue.Add(bitmap.GetPixel(x, y).GetHue());
                }
                float fHue = ColorFunctions.AverageHue(aAvgHue);
                aAvgHue.Clear();
                g.DrawLine(Pens.Blue, x, bmp2.Height, x, bmp2.Height - fHue);
            }
            return bmp2;
        }

        /// <summary>
        /// Hues the profile.
        /// </summary>
        /// <param name="_bitmap">The _bitmap.</param>
        /// <returns></returns>
        public static Bitmap HueProfile(Bitmap _bitmap)
        {
            int x = 0;
            int y = 0;

            UnsafeBitmap bitmap = _bitmap;
            Bitmap bmp2 = new Bitmap(bitmap.Width, bitmap.Height);
            float fHue = 0.0f;

            int nHeight = bitmap.Height;
            int nWidth = bitmap.Width;

            for (x = 0; x < nWidth; x++)
            {
                for (y = 0; y < nHeight; y++)
                {
                    fHue = bitmap.GetPixel(x, y).GetHue() * 0.708333333f;
                    Color color = Color.FromArgb(0, 0, (int)fHue);
                    bmp2.SetPixel(x, y, color);
                }
            }
            bitmap.Dispose();
            return bmp2;
        }

        /// <summary>
        /// Columnwise measuring of saturation
        /// This is done by first measuring the average Color of this column
        /// </summary>
        /// <param name="_bitmap">The _bitmap.</param>
        /// <returns></returns>
        public static Bitmap AverageColor(Bitmap _bitmap)
        {
            int x = 0;
            int y = 0;

            UnsafeBitmap bitmap = _bitmap;
            Bitmap bmp2 = new Bitmap(bitmap.Width, bitmap.Height);
            Graphics g = Graphics.FromImage(bmp2);

            g.FillRectangle(Brushes.Black, new Rectangle(0, 0, bmp2.Width, bmp2.Height));

            int nWidth = bitmap.Width;
            int nHeight = bitmap.Height;

            for (x = 0; x < nWidth; x++)
            {
                List<Color> aAvgColor = new List<Color>();
                aAvgColor.Clear();
                for (y = 0; y < nHeight; y++)
                {
                    aAvgColor.Add(bitmap.GetPixel(x, y));
                }
                Color avgColor = ColorFunctions.AverageColor(aAvgColor);
                avgColor = Color.FromArgb(0, avgColor);

                float fColor = avgColor.ToArgb() / 16777215.0f;
                g.DrawLine(Pens.Blue, x, bmp2.Height, x, bmp2.Height - fColor * 255);
            }
            bitmap.Dispose();
            return bmp2;
        }

        /// <summary>
        /// Columnwise measuring of saturation
        /// This is done by first measuring the average Color of this column
        /// </summary>
        /// <param name="_bitmap">The _bitmap.</param>
        /// <returns></returns>
        public static Bitmap ColorProfile(Bitmap _bitmap)
        {
            int x = 0;
            int y = 0;

            UnsafeBitmap bitmap = _bitmap;
            Bitmap bmp2 = new Bitmap(bitmap.Width, bitmap.Height);

            int nHeight = bitmap.Height;
            int nWidth = bitmap.Width;

            for (x = 0; x < nWidth; x++)
            {
                for (y = 0; y < nHeight; y++)
                {
                    bmp2.SetPixel(x, y, bitmap.GetPixel(x, y));
                }
            }
            bitmap.Dispose();
            return bmp2;
        }

        /// <summary>
        /// Ys the cb cr.
        /// </summary>
        /// <param name="bitmap">The bitmap.</param>
        /// <returns></returns>
        public static Bitmap YCbCr(Bitmap bitmap)
        {
            int x = 0;
            int y = 0;

            Bitmap bmp2 = new Bitmap(bitmap.Width, bitmap.Height);
            Graphics g = Graphics.FromImage(bmp2);

            g.FillRectangle(Brushes.Black, new Rectangle(0, 0, bmp2.Width, bmp2.Height));

            int nWidth = bitmap.Width;
            int nHeight = bitmap.Height;

            for (x = 0; x < nWidth; x++)
            {
                List<YCbCr> aColor = new List<YCbCr>();
                for (y = 0; y < nHeight; y++)
                {
                    aColor.Add(new YCbCr(bitmap.GetPixel(x, y)));
                }
                //float fValue = new YCbCr().;
                aColor.Clear();
                //g.DrawLine(Pens.Blue, x, bmp2.Height, x, bmp2.Height - fValue * 500);
            }
            return bmp2;
        }

        /// <summary>
        /// Columnwise measuring of saturation
        /// This is done by first measuring the average Color of this column
        /// </summary>
        /// <param name="_bitmap">The _bitmap.</param>
        /// <returns></returns>
        public static Bitmap AverageBrightness(UnsafeBitmap _bitmap)
        {
            int x = 0;
            int y = 0;

            UnsafeBitmap bitmap = _bitmap;
            Bitmap bmp2 = new Bitmap(bitmap.Width, bitmap.Height);
            Graphics g = Graphics.FromImage(bmp2);

            g.FillRectangle(Brushes.Black, new Rectangle(0, 0, bmp2.Width, bmp2.Height));

            int nWidth = bitmap.Width;
            int nHeight = bitmap.Height;

            for (x = 0; x < nWidth; x++)
            {
                List<float> aBrightness = new List<float>();
                for (y = 0; y < nHeight; y++)
                {
                    aBrightness.Add(bitmap.GetPixel(x, y).GetBrightness());
                }
                float fValue = ColorFunctions.AverageBrightness(aBrightness);
                aBrightness.Clear();
                g.DrawLine(Pens.Blue, x, bmp2.Height, x, bmp2.Height - fValue * 500);
            }
            bitmap.Dispose();
            return bmp2;
        }

        /// <summary>
        /// Columnwise measuring of saturation
        /// This is done by first measuring the average Color of this column
        /// </summary>
        /// <param name="bitmap"></param>
        /// <returns></returns>
        public static Bitmap BrightnessProfile(Bitmap bitmap)
        {
            int x = 0;
            int y = 0;

            Bitmap bmp2 = new Bitmap(bitmap.Width, bitmap.Height);
            float fBrightness = 0.0f;

            int nHeight = bitmap.Height;
            int nWidth = bitmap.Width;

            for (x = 0; x < nWidth; x++)
            {
                for (y = 0; y < nHeight; y++)
                {
                    fBrightness = bitmap.GetPixel(x, y).GetBrightness() * 255;
                    Color color = Color.FromArgb(0, 0, (int)fBrightness);
                    bmp2.SetPixel(x, y, color);
                }
            }
            return bmp2;
        }

        /// <summary>
        /// Columnwise measuring of saturation
        /// This is done by first measuring the average Color of this column
        /// </summary>
        /// <param name="bitmap"></param>
        /// <returns></returns>
        public static Bitmap AverageSaturation(Bitmap bitmap)
        {
            int x = 0;
            int y = 0;

            Bitmap bmp2 = new Bitmap(bitmap.Width, bitmap.Height);
            Graphics g = Graphics.FromImage(bmp2);

            g.FillRectangle(Brushes.Black, new Rectangle(0, 0, bmp2.Width, bmp2.Height));

            int nHeight = bitmap.Height;
            int nWidth = bitmap.Width;

            for (x = 0; x < nWidth; x++)
            {
                List<float> aAvgSaturation = new List<float>();
                for (y = 0; y < nHeight; y++)
                {
                    aAvgSaturation.Add(bitmap.GetPixel(x, y).GetSaturation());
                }
                float fSaturation = ColorFunctions.AverageSaturation(aAvgSaturation);
                aAvgSaturation.Clear();
                g.DrawLine(Pens.Blue, x, bmp2.Height, x, bmp2.Height - fSaturation * 500);
            }
            return bmp2;
        }

        /// <summary>
        /// Columnwise measuring of saturation
        /// This is done by first measuring the average Color of this column
        /// </summary>
        /// <param name="bitmap"></param>
        /// <returns></returns>
        public static Bitmap SaturationProfile(Bitmap bitmap)
        {
            int x = 0;
            int y = 0;

            Bitmap bmp2 = new Bitmap(bitmap.Width, bitmap.Height);

            int nHeight = bitmap.Height;
            int nWidth = bitmap.Width;

            float fSaturation = 0.0f;
            for (x = 0; x < nWidth; x++)
            {
                List<float> aAvgSaturation = new List<float>();
                for (y = 0; y < nHeight; y++)
                {
                    fSaturation = bitmap.GetPixel(x, y).GetSaturation() * 255;
                    Color color = Color.FromArgb(0, 0, (int)fSaturation);
                    bmp2.SetPixel(x, y, color);
                }
            }
            return bmp2;
        }

        /// <summary>
        /// Columnwise measuring of saturation
        /// This is done by first measuring the average Color of this column
        /// </summary>
        /// <param name="bitmap"></param>
        /// <returns></returns>
        public static Bitmap AverageLuminance(Bitmap bitmap)
        {
            int x = 0;
            int y = 0;

            Bitmap bmp2 = new Bitmap(bitmap.Width, bitmap.Height);
            Graphics g = Graphics.FromImage(bmp2);

            g.FillRectangle(Brushes.Black, new Rectangle(0, 0, bmp2.Width, bmp2.Height));

            int nHeight = bitmap.Height;
            int nWidth = bitmap.Width;

            for (x = 0; x < nWidth; x++)
            {
                List<float> aLuminance = new List<float>();
                Color colorAvg = Color.Transparent;
                for (y = 0; y < nHeight; y++)
                {
                    aLuminance.Add(ColorFunctions.GetLuminance(bitmap.GetPixel(x, y)));
                }
                float fValue = ColorFunctions.AverageLuminance(aLuminance);
                aLuminance.Clear();
                g.DrawLine(Pens.Blue, x, bmp2.Height, x, bmp2.Height - fValue);
            }
            return bmp2;
        }


        /// <summary>
        /// Columnwise measuring of saturation
        /// This is done by first measuring the average Color of this column
        /// </summary>
        /// <param name="bitmap"></param>
        /// <returns></returns>
        public static Bitmap LuminanceProfile(Bitmap bitmap)
        {
            int x = 0;
            int y = 0;

            Bitmap bmp2 = new Bitmap(bitmap.Width, bitmap.Height);

            Color c = Color.FromArgb(255, 255, 255);
            float fValue = c.R * 0.3f + c.G * 0.59f + c.B * 0.11f;

            float fLuminance = 0.0f;

            int nHeight = bitmap.Height;
            int nWidth = bitmap.Width;

            for (x = 0; x < nWidth; x++)
            {
                List<float> aLuminance = new List<float>();
                for (y = 0; y < nHeight; y++)
                {
                    Color color = bitmap.GetPixel(x, y);
                    fLuminance = ColorFunctions.GetLuminance(color);
                    color = Color.FromArgb(0, 0, (int)fLuminance);
                    bmp2.SetPixel(x, y, color);
                }
                aLuminance.Clear();
            }
            return bmp2;
        }

        /// <summary>
        /// Gets the color dictionary.
        /// </summary>
        /// <value>The color dictionary.</value>
        public Dictionary<Color, int> ColorDictionary
        {
            get { return m_aColor; }
        }

        /// <summary>
        /// Gets the color list.
        /// </summary>
        /// <value>The color list.</value>
        public List<KeyValuePair<Color, int>> ColorList
        {
            get { return m_aColorList; }
        }

        /// <summary>
        /// Gets the data.
        /// </summary>
        /// <value>The data.</value>
        public List<StatisticValue> Data
        {
            get { return m_aData; }
        }

        /// <summary>
        /// Gets the <see cref="StatisticValue"/> with the specified _n index.
        /// </summary>
        /// <value></value>
        public StatisticValue this[int _nIndex]
        {
            get { return m_aData[_nIndex]; }
        }

        /// <summary>
        /// Gets the count.
        /// </summary>
        /// <value>The count.</value>
        public int Count
        {
            get { return m_aData.Count; }
        }

        /// <summary>
        /// Sorts by specified processing mode.
        /// </summary>
        /// <param name="_sortMode">The _sort mode.</param>
        public void SortBy(PROCESSING_MODE _sortMode)
        {
            if (_sortMode != PROCESSING_MODE.ColorCount)
            {
                this.m_aData.Sort(new ValueSorter(_sortMode));
            }
            else
            {
                this.m_aColorList.Sort(new ColorCountSorter());
            }
        }

        /// <summary>
        /// Sorts by specified processing mode.
        /// </summary>
        /// <param name="_sortMode"></param>
        public void SortColorDictionaryBy(PROCESSING_MODE _sortMode)
        {
            if (_sortMode != PROCESSING_MODE.ColorCount)
            {
                this.m_aColorList.Sort(new ValueSorterColorDictionary(_sortMode));
            }
            else
            {
                this.m_aColorList.Sort(new ColorCountSorter());
            }
        }

        /// <summary>
        /// Compares the color.
        /// </summary>
        /// <param name="x">The x.</param>
        /// <param name="y">The y.</param>
        /// <returns></returns>
        public static int CompareColor(int x, int y)
        {
            if (x > y)
            {
                return 1;
            }
            else if (x < y)
            {
                return -1;
            }
            else
            {
                return 0;
            }
        }

        /// <summary>
        /// Compares the A channel.
        /// </summary>
        /// <param name="a1">The a1.</param>
        /// <param name="a2">The a2.</param>
        /// <returns></returns>
        public static int CompareA(int a1, int a2)
        {
            if (a1 > a2)
            {
                return 1;
            }
            else if (a2 > a1)
            {
                return -1;
            }
            else
            {
                return 0;
            }
        }

        /// <summary>
        /// Compares the R channel.
        /// </summary>
        /// <param name="a1">The a1.</param>
        /// <param name="a2">The a2.</param>
        /// <returns></returns>
        public static int CompareR(int a1, int a2)
        {
            if (a1 > a2)
            {
                return 1;
            }
            else if (a2 > a1)
            {
                return -1;
            }
            else
            {
                return 0;
            }
        }

        /// <summary>
        /// Compares the G channel.
        /// </summary>
        /// <param name="a1">The a1.</param>
        /// <param name="a2">The a2.</param>
        /// <returns></returns>
        public static int CompareG(int a1, int a2)
        {
            if (a1 > a2)
            {
                return 1;
            }
            else if (a2 > a1)
            {
                return -1;
            }
            else
            {
                return 0;
            }
        }


        /// <summary>
        /// Compares the B channel.
        /// </summary>
        /// <param name="a1">The a1.</param>
        /// <param name="a2">The a2.</param>
        /// <returns></returns>
        public static int CompareB(int a1, int a2)
        {
            if (a1 > a2)
            {
                return 1;
            }
            else if (a2 > a1)
            {
                return -1;
            }
            else
            {
                return 0;
            }
        }

        /// <summary>
        /// Compares the luminance.
        /// </summary>
        /// <param name="fLuminance1">The f luminance1.</param>
        /// <param name="fLuminance2">The f luminance2.</param>
        /// <returns></returns>
        public static int CompareLuminance(float fLuminance1, float fLuminance2)
        {
            if (fLuminance1 > fLuminance2)
            {
                return 1;
            }
            else if (fLuminance2 > fLuminance1)
            {
                return -1;
            }
            else
            {
                return 0;
            }
        }

        /// <summary>
        /// Compares the brightness.
        /// </summary>
        /// <param name="fBrightness1">The f brightness1.</param>
        /// <param name="fBrightness2">The f brightness2.</param>
        /// <returns></returns>
        public static int CompareBrightness(float fBrightness1, float fBrightness2)
        {
            if (fBrightness1 > fBrightness2)
            {
                return 1;
            }
            else if (fBrightness2 > fBrightness1)
            {
                return -1;
            }
            else
            {
                return 0;
            }
        }

        /// <summary>
        /// Compares the saturation.
        /// </summary>
        /// <param name="fSaturation1">The f saturation1.</param>
        /// <param name="fSaturation2">The f saturation2.</param>
        /// <returns></returns>
        public static int CompareSaturation(float fSaturation1, float fSaturation2)
        {
            if (fSaturation1 > fSaturation2)
            {
                return 1;
            }
            else if (fSaturation2 > fSaturation1)
            {
                return -1;
            }
            else
            {
                return 0;
            }
        }

        /// <summary>
        /// Compares the hue.
        /// </summary>
        /// <param name="fHue1">The f hue1.</param>
        /// <param name="fHue2">The f hue2.</param>
        /// <returns></returns>
        public static int CompareHue(float fHue1, float fHue2)
        {
            if (fHue1 > fHue2)
            {
                return 1;
            }
            else if (fHue2 > fHue1)
            {
                return -1;
            }
            else
            {
                return 0;
            }
        }

        /// <summary>
        /// Compares the sum RGB.
        /// </summary>
        /// <param name="nSum1">The n sum1.</param>
        /// <param name="nSum2">The n sum2.</param>
        /// <returns></returns>
        public static int CompareSumRGB(int nSum1, int nSum2)
        {
            if (nSum1 > nSum2)
            {
                return 1;
            }
            else if (nSum2 > nSum1)
            {
                return -1;
            }
            else
            {
                return 0;
            }
        }

        /// <summary>
        /// Compares the sum ARGB.
        /// </summary>
        /// <param name="nSum1">The n sum1.</param>
        /// <param name="nSum2">The n sum2.</param>
        /// <returns></returns>
        public static int CompareSumARGB(int nSum1, int nSum2)
        {
            if (nSum1 > nSum2)
            {
                return 1;
            }
            else if (nSum2 > nSum1)
            {
                return -1;
            }
            else
            {
                return 0;
            }
        }

        /// <summary>
        /// Compares the mul ARGB.
        /// </summary>
        /// <param name="nSum1">The n sum1.</param>
        /// <param name="nSum2">The n sum2.</param>
        /// <returns></returns>
        public static int CompareMulARGB(int nSum1, int nSum2)
        {
            if (nSum1 > nSum2)
            {
                return 1;
            }
            else if (nSum2 > nSum1)
            {
                return -1;
            }
            else
            {
                return 0;
            }
        }

        /// <summary>
        /// Compares the mul RGB.
        /// </summary>
        /// <param name="nSum1">The n sum1.</param>
        /// <param name="nSum2">The n sum2.</param>
        /// <returns></returns>
        public static int CompareMulRGB(int nSum1, int nSum2)
        {
            if (nSum1 > nSum2)
            {
                return 1;
            }
            else if (nSum2 > nSum1)
            {
                return -1;
            }
            else
            {
                return 0;
            }
        }
    }
}


